#pragma once
#include "CTokens.h"

class CScript;
class CSubScript;

class CCompiler
{
	static CLinkPtr<const CToken*>	s_pTokens,
									s_pBadToken;
	static CScript				*	s_pScript;
	static CSubScript			*	s_pSubScript;
	static CFile				*	s_pOutFile;
	static CParser::sAsmStruct	*	s_pAsmStruct;
	static int						s_nVarDeclarationType,	// (basic type)
									s_nNumBytesWritten,
									s_nNumLinesEncoded,
									s_nNumTokensEncoded,
									s_nNumBytesBuffered,
									s_nNumNamelessScripts;
	static bool						s_bInConsoleMode;
	static BYTE 				*	s_pCompilationBuffer,
									s_bCompilationBuffer[COMPILATION_BUFFER_LENGTH];
	static DWORD					s_dwLabelOffset;

	/*static CScript			*	s_pScript;
	static CSubScript		*	s_pSubScript;
	static CCommand			*	s_pCommand;
	static CVariable		*	s_pVariable;
	static CLabel			*	s_pLabel;
	static COperator 		*	s_pOperator;
	static COperation 		*	s_pOperations[MAX_INLINE_OPERATIONS];
	static CControlStruct	*	s_pControlStructure;*/

	static void WriteParams(const CToken *);
	static void WriteParam(const CTypeBase *, const CToken *);
	static void WriteValue(int val, eDataType size);
	static void WriteValue(float val, eDataType size);

	static void InitBuffer()
	{
		s_pCompilationBuffer = new BYTE[COMPILATION_BUFFER_LENGTH];
		memset(s_pCompilationBuffer, 0, COMPILATION_BUFFER_LENGTH);
		s_nNumBytesBuffered = 0;
	}

	static void ClearBuffer()
	{
		s_pCompilationBuffer = s_bCompilationBuffer;
		memset(s_bCompilationBuffer, 0, sizeof(s_bCompilationBuffer));
	}

	static void FreeBuffer()
	{
		delete[] s_pCompilationBuffer;
	}

	static void AddToBuffer(BYTE * buff, size_t size)
	{
		BYTE * pBuff = &s_pCompilationBuffer[s_nNumBytesBuffered];
		memcpy(pBuff, buff, size);
		s_nNumBytesBuffered += size;
	}

	static inline int GetTokenValueSize(const CToken * pToken)
	{
		switch(pToken->GetType())
		{
		case TOKEN_LABEL:
		case TOKEN_VALUE:		return pToken->GetValueType() == PT_FLOAT ? sizeof(float) : GetIntNumBytes(pToken->GetIntValue());

		case TOKEN_STRING:		return pToken->GetIntValue();
		case TOKEN_VAR:			return GetIntNumBytes(pToken->GetVariableValue()->GetIndex());
		}
		return 0;
	}

	static const CToken * GetNextCompilationToken()
	{
		while(true)
		{
			if(s_pTokens != s_pBadToken)
			{
				if(!s_pTokens->IsSkippedDuringCompilation())
					return *s_pTokens++;
			}
			else break;
			
			++s_pTokens;
		}
		return nullptr;
	}

	static const CToken * PeekNextCompilationToken()
	{
		auto pTokens = s_pTokens;
		while(true)
		{
			if(pTokens != s_pBadToken)
			{
				if(!pTokens->IsSkippedDuringCompilation())
					return *pTokens++;
			}
			else break;
			
			++pTokens;
		}
		return nullptr;
	}

	static void Error(const char *szStr)
	{
		static char szCompileError[2048];
		Print(SCRambl.BuildText(SCRambl.GetText("COMPILER","ERROR"), szCompileError, sizeof(szCompileError), "%s", szStr));
	}
	static void Warning(const char *szStr)
	{
		static char szCompileWarning[2048];
		Print(SCRambl.BuildText(SCRambl.GetText("COMPILER","WARNING"),szCompileWarning, sizeof(szCompileWarning), "%s", szStr));
	}

public:
	static int Compile(CScript *);
	static int Compile(CSubScript *, CFile *);
	
	static void Init(CLinkPtr<const CToken*> pFirstToken, CLinkPtr<const CToken*> pBadToken)
	{
		CLabels::Reset();
		CVariables::Reset();
		CControlStructs::Reset();

		s_pTokens = pFirstToken;
		s_pBadToken = pBadToken;
		InitBuffer();
		s_nNumBytesWritten = 0;
		s_nNumLinesEncoded = 0;
		s_nNumNamelessScripts = 0;
	}
};

extern CCompiler Compiler;